/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "securec.h"
#include "scan_service_proxy.h"
#include "iremote_broker.h"
#include "napi_scan_utils.h"
#include "scan_constant.h"
#include "scan_log.h"
#include "scanner_info.h"

namespace OHOS::Scan {
using namespace OHOS::HiviewDFX;

ScanServiceProxy::ScanServiceProxy(const sptr<IRemoteObject> &object) : IRemoteProxy<IScanService>(object) {}

int32_t ScanServiceProxy::GetResult(int32_t retCode, MessageParcel &reply)
{
    if (retCode != ERR_NONE) {
        SCAN_HILOGE("rpc error code = %{public}d", retCode);
        return E_SCAN_RPC_FAILURE;
    }

    retCode = reply.ReadInt32();
    SCAN_HILOGE("ScanServiceProxy end. ret = [%{public}d]", retCode);
    return retCode;    
}

int32_t ScanServiceProxy::InitScan(int32_t &scanVersion)
{
    MessageParcel data, reply;
    MessageOption option;
    data.WriteInterfaceToken(GetDescriptor());
    SCAN_HILOGE("ScanServiceProxy InitScan start");
    int32_t ret = Remote()->SendRequest(CMD_INIT_SCAN, data, reply, option);
    ret = GetResult(ret, reply);
    if (ret == E_SCAN_NONE) {
        scanVersion = reply.ReadInt32();
    }    
    SCAN_HILOGD("ScanServiceProxy InitScan end.");
    return ret;
}

int32_t ScanServiceProxy::ExitScan()
{
    MessageParcel data, reply;
    MessageOption option;
    data.WriteInterfaceToken(GetDescriptor());
    SCAN_HILOGE("ScanServiceProxy ExitScan start");
    int32_t ret = Remote()->SendRequest(CMD_EXIT_SCAN, data, reply, option);
    ret = GetResult(ret, reply);
    SCAN_HILOGD("ScanServiceProxy ExitScan end");
    return ret;
}

int32_t ScanServiceProxy::GetScannerList()
{
    MessageParcel data, reply;
    MessageOption option;
    data.WriteInterfaceToken(GetDescriptor());
    SCAN_HILOGE("ScanServiceProxy GetScannerList start");
    int32_t ret = Remote()->SendRequest(CMD_GET_SCANNER_LIST, data, reply, option);
    ret = GetResult(ret,reply);
    if(ret != E_SCAN_NONE){
        SCAN_HILOGE("ScanServiceProxy GetScannerList failed");
        return ret;
    }
    SCAN_HILOGD("ScanServiceProxy GetScannerList end. ret = [%{public}d]", ret);
    return ret;
}


int32_t ScanServiceProxy::StopDiscover()
{
    MessageParcel data, reply;
    MessageOption option;
    data.WriteInterfaceToken(GetDescriptor());
    SCAN_HILOGE("ScanServiceProxy GetScannerList start");
    int32_t ret = Remote()->SendRequest(CMD_STOP_DISCOVER, data, reply, option);
    ret = GetResult(ret,reply);
    if(ret != E_SCAN_NONE){
        SCAN_HILOGE("ScanServiceProxy GetScannerList failed");
        return ret;
    }
    SCAN_HILOGD("ScanServiceProxy GetScannerList end. ret = [%{public}d]", ret);
    return ret;
}


int32_t ScanServiceProxy::OpenScanner(const std::string scannerId)
{
    MessageParcel data, reply;
    MessageOption option;
    data.WriteInterfaceToken(GetDescriptor());
    SCAN_HILOGE("ScanServiceProxy OpenScanner start");
    data.WriteString(scannerId);
    int32_t ret = Remote()->SendRequest(CMD_OPEN_SCANNER, data, reply, option);
    ret = GetResult(ret, reply);
    SCAN_HILOGD("ScanServiceProxy OpenScanner end. ret = [%{public}d]", ret);
    return ret;
}

int32_t ScanServiceProxy::CloseScanner(const std::string scannerId)
{
    MessageParcel data, reply;
    MessageOption option;
    data.WriteInterfaceToken(GetDescriptor());
    SCAN_HILOGE("ScanServiceProxy CloseScanner start");
    data.WriteString(scannerId);
    int32_t ret = Remote()->SendRequest(CMD_CLOSE_SCANNER, data, reply, option);
    ret = GetResult(ret, reply);
    SCAN_HILOGD("ScanServiceProxy CloseScanner end. ret = [%{public}d]", ret);
    return ret;
}

int32_t ScanServiceProxy::GetScanOptionDesc(const std::string scannerId, const int32_t optionIndex, ScanOptionDescriptor &desc)
{
    MessageParcel data, reply;
    MessageOption option;
    data.WriteInterfaceToken(GetDescriptor());
    SCAN_HILOGE("ScanServiceProxy GetScanOptionDesc start");
    data.WriteString(scannerId);
    data.WriteInt32(optionIndex);
    int32_t ret = Remote()->SendRequest(CMD_GET_SCAN_OPTION_DESC, data, reply, option);
    ret = GetResult(ret, reply);
    if (ret == E_SCAN_NONE) {
        auto scanOptionDescriptor = ScanOptionDescriptor::Unmarshalling(reply);
        desc = *scanOptionDescriptor;
    }
    SCAN_HILOGD("ScanServiceProxy GetScanOptionDesc end. ret = [%{public}d]", ret);
    return ret;
}

int32_t ScanServiceProxy::OpScanOptionValue(const std::string scannerId, const int32_t optionIndex, const ScanOptionOpType op, ScanOptionValue &value, int32_t &info)
{
    MessageParcel data, reply;
    MessageOption option;
    data.WriteInterfaceToken(GetDescriptor());
    SCAN_HILOGE("ScanServiceProxy OpScanOptionValue start");
    data.WriteString(scannerId);
    data.WriteInt32(optionIndex);
    data.WriteUint32(op);
    value.Marshalling(data);
    int32_t ret = Remote()->SendRequest(CMD_OP_SCAN_OPTION_VALUE, data, reply, option);
    ret = GetResult(ret, reply);
    if (ret == E_SCAN_NONE) {
        auto scanOptionValue = ScanOptionValue::Unmarshalling(reply);
        value = *scanOptionValue;
        if (op == SCAN_ACTION_GET_VALUE) {
            info = reply.ReadInt32();
        }
    }
    SCAN_HILOGD("ScanServiceProxy OpScanOptionValue end. ret = [%{public}d]", ret);
    return ret;
}

int32_t ScanServiceProxy::GetScanParameters(const std::string scannerId, ScanParameters &para)
{
    MessageParcel data, reply;
    MessageOption option;
    data.WriteInterfaceToken(GetDescriptor());
    SCAN_HILOGE("ScanServiceProxy GetScanParameters start");
    data.WriteString(scannerId);
    int32_t ret = Remote()->SendRequest(CMD_GET_SCAN_PARAMETERS, data, reply, option);
    ret = GetResult(ret, reply);
    if (ret == E_SCAN_NONE) {
        auto scanParameters = ScanParameters::Unmarshalling(reply);
        para = *scanParameters;
    }
    SCAN_HILOGD("ScanServiceProxy GetScanParameters end. ret = [%{public}d]", ret);
    return ret;
}

int32_t ScanServiceProxy::StartScan(const std::string scannerId)
{
    MessageParcel data, reply;
    MessageOption option;
    data.WriteInterfaceToken(GetDescriptor());
    SCAN_HILOGE("ScanServiceProxy StartScan start");
    data.WriteString(scannerId);
    int32_t ret = Remote()->SendRequest(CMD_START_SCAN, data, reply, option);
    ret = GetResult(ret, reply);
    SCAN_HILOGD("ScanServiceProxy StartScan end. ret = [%{public}d]", ret);
    return ret;
}

int32_t ScanServiceProxy::GetSingleFrame(const std::string scannerId, int32_t &size, uint8_t **frameData)
{
    MessageParcel data, reply;
    MessageOption option;
    data.WriteInterfaceToken(GetDescriptor());
    SCAN_HILOGE("ScanServiceProxy GetSingleFrame start");
    data.WriteString(scannerId);
    int32_t ret = Remote()->SendRequest(CMD_GET_SINGLE_FRAME, data, reply, option);
    ret = GetResult(ret, reply);
    if (ret == E_SCAN_NONE) {
        size = reply.ReadInt32();
        SCAN_HILOGE("ScanServiceProxy GetSingleFrame buffersize [%{public}d]", size);
        *frameData = (uint8_t *)malloc(size);
        if (!*frameData) {
            SCAN_HILOGE("malloc memory for data failed!!!");
            return E_SCAN_NO_MEM;
        }
        const uint8_t *buffer = reply.ReadBuffer(size);
        if (buffer == nullptr) {
            SCAN_HILOGE("failed to read buffer");
            return E_SCAN_NO_MEM;
        }
        memcpy_s(*frameData, size, buffer, size);
    }
    SCAN_HILOGE("ScanServiceProxy GetSingleFrame end. ret = [%{public}d]", ret);
    return ret;
}

int32_t ScanServiceProxy::GetSingleFrameFD(const std::string scannerId, int32_t &size, uint32_t fd)
{
    MessageParcel data, reply;
    MessageOption option;
    data.WriteInterfaceToken(GetDescriptor());
    SCAN_HILOGE("ScanServiceProxy GetSingleFrameFD start");
    data.WriteString(scannerId);
    data.WriteFileDescriptor(fd);
    int32_t ret = Remote()->SendRequest(CMD_GET_SINGLE_FRAME_FD, data, reply, option);
    ret = GetResult(ret, reply);
    if (ret == E_SCAN_NONE) {
        size = reply.ReadUint32();
    }    
    SCAN_HILOGE("ScanServiceProxy GetSingleFrameFD end. ret = [%{public}d]", ret);
    return ret;
}

int32_t ScanServiceProxy::CancelScan(const std::string scannerId)
{
    MessageParcel data, reply;
    MessageOption option;
    data.WriteInterfaceToken(GetDescriptor());
    SCAN_HILOGE("ScanServiceProxy CancelScan start");
    data.WriteString(scannerId);
    int32_t ret = Remote()->SendRequest(CMD_CANCEL_SCAN, data, reply, option);
    ret = GetResult(ret, reply);
    SCAN_HILOGD("ScanServiceProxy CancelScan end. ret = [%{public}d]", ret);
    return ret;
}

int32_t ScanServiceProxy::SetScanIOMode(const std::string scannerId, const bool isNonBlocking)
{
    MessageParcel data, reply;
    MessageOption option;
    data.WriteInterfaceToken(GetDescriptor());
    SCAN_HILOGE("ScanServiceProxy SetScanIOMode start");
    data.WriteString(scannerId);
    data.WriteBool(isNonBlocking);
    int32_t ret = Remote()->SendRequest(CMD_SET_SCAN_IO_MODE, data, reply, option);
    ret = GetResult(ret, reply);
    SCAN_HILOGD("ScanServiceProxy SetScanIOMode end. ret = [%{public}d]", ret);
    return ret;
}

int32_t ScanServiceProxy::GetScanSelectFd(const std::string scannerId, int32_t &fd)
{
    MessageParcel data, reply;
    MessageOption option;
    data.WriteInterfaceToken(GetDescriptor());
    SCAN_HILOGE("ScanServiceProxy GetScanSelectFd start");
    data.WriteString(scannerId);
    int32_t ret = Remote()->SendRequest(CMD_GET_SCAN_SELECT_FD, data, reply, option);
    ret = GetResult(ret, reply);
    if (ret == E_SCAN_NONE) {
        fd = reply.ReadInt32();
    }
    SCAN_HILOGD("ScanServiceProxy GetScanSelectFd end. ret = [%{public}d]", ret);
    return ret;
}

int32_t ScanServiceProxy::On(const std::string taskId, const std::string &type, const sptr<IScanCallback> &listener)
{
    if (listener == nullptr) {
        SCAN_HILOGE("listener is nullptr");
        return E_SCAN_INVALID_PARAMETER;
    }

    if (type.empty()) {
        SCAN_HILOGE("ScanServiceProxy::On type is null.");
        return E_SCAN_INVALID_PARAMETER;
    }

    MessageParcel data, reply;
    MessageOption option;

    data.WriteInterfaceToken(GetDescriptor());
    data.WriteString(taskId);
    data.WriteString(type);
    data.WriteRemoteObject(listener->AsObject().GetRefPtr());
    int32_t ret = Remote()->SendRequest(CMD_ON, data, reply, option);
    if (ret != ERR_NONE) {
        SCAN_HILOGE("On, rpc error code = %{public}d", ret);
        return E_SCAN_RPC_FAILURE;
    }

    ret = reply.ReadInt32();
    SCAN_HILOGD("ScanServiceProxy On out. ret = [%{public}d]", ret);
    return ret;
}

int32_t ScanServiceProxy::Off(const std::string taskId, const std::string &type)
{
    SCAN_HILOGD("ScanServiceProxy::Off in");
    if (type.empty()) {
        SCAN_HILOGE("ScanServiceProxy::On type is null.");
        return E_SCAN_INVALID_PARAMETER;
    }

    MessageParcel data, reply;
    MessageOption option;

    data.WriteInterfaceToken(GetDescriptor());
    data.WriteString(taskId);
    data.WriteString(type);
    int32_t ret = Remote()->SendRequest(CMD_OFF, data, reply, option);
    if (ret != ERR_NONE) {
        SCAN_HILOGE("On, rpc error code = %{public}d", ret);
        return E_SCAN_RPC_FAILURE;
    }

    ret = reply.ReadInt32();
    SCAN_HILOGD("ScanServiceProxy Off out. ret = [%{public}d]", ret);
    return ret;
}

} // namespace OHOS::Scan
